package com.m1.tzolkin.model.board;

import java.util.Collection;
import java.util.HashSet;

import com.m1.tzolkin.model.Season;
import com.m1.tzolkin.model.TZResource;
import com.m1.tzolkin.model.exceptions.EndOfGameException;
import com.m1.tzolkin.model.exceptions.NoMovedWorkersException;
import com.m1.tzolkin.model.exceptions.NotEnoughCornException;
import com.m1.tzolkin.model.exceptions.StepMoveException;
import com.m1.tzolkin.model.exceptions.WaitingOperationsException;
import com.m1.tzolkin.model.players.ITZPlayer;
import com.m1.tzolkin.model.temples.ITemple;
import com.m1.tzolkin.model.temples.TempleEnum;

public class TechBoard extends BuildBoard implements ITechBoard {
	
	// ATTRIBUTS
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 602007993010769677L;
	// Monter de technologies
	private int upTechs;
	// Descendre dans des temples
	private int downTemples;
	// Monter dans des temples
	private int upTemples;
	// Monter d'une marche dans des temples diff�rents
	protected Collection<ITemple> differentTemples;
	private int upDifferentTemples;
	// Echanger des ressources au march�
	private boolean canExchange;
	// Vrai si il faut payer pour monter dans la technologie
	private boolean mustPayTech;
	// La quantit� de ressources quelconques que le joueur peut choisir
	private int collectResource;
	
	// CONSTRUCTEUR
	
	public TechBoard(Collection<ITZPlayer> players) {
		super(players);
		differentTemples = new HashSet<ITemple>();
		initPermissions();
	}
	
	// REQUETES

	@Override
	public int canUpTechs() {
		return upTechs;
	}
	
	@Override
	public int mustDownTemples() {
		return downTemples;
	}

	@Override
	public int canUpTemples() {
		return upTemples;
	}

	@Override
	public Collection<ITemple> getUpableTemples() {
		return differentTemples;
	}
	
	@Override
	public int canUpDifferentTemples() {
		return upDifferentTemples;
	}

	@Override
	public boolean canExchange() {
		return canExchange;
	}

	@Override
	public int canCollectResource() {
		return collectResource;
	}
	
	// COMMANDES
	
	@Override
	public void askForCorn() {
		ITZPlayer p = getCurrentPlayer();
		if (p.getCorn() >= LIMIT_CORN_FOR_ASK
				|| getRemovedWorkers() != 0 || getPlacedWorkers() != 0) {
			throw new IllegalStateException();
		}
		p.addCorn(LIMIT_CORN_FOR_ASK - p.getCorn());
		setDownTemples(1);
		getLog().addSentence(new String[] {
			getCurrentPlayer().getName(), "ASK_FOR_CORN", "AND", "MUST", "TO_DOWN", "IN", "1", "TEMPLE"	
		});
		listeners.firePropertyChange("begforcorn", getCurrentPlayer().getCorn() < LIMIT_CORN_FOR_ASK, false);
	}
	
	@Override
	public void changeResource(TZResource r) {
		if (isWaitingForTurn() != 0) {
			throw new IllegalStateException();
		}
		if (r == null) {
			throw new IllegalArgumentException();
		}
		if (getPlayersManager().getCurrent().getWallet().getResources(r) < 1 || !canExchange()) {
			throw new IllegalStateException();
		}
		getCurrentPlayer().getWallet().removeResource(r);
		getCurrentPlayer().addCorn((int) r.getAbsoluteValue());
		getLog().addSentence(new String[] {
			getCurrentPlayer().getName(), "CHANGE", "1", r.toString(), "FOR", "" + (int) r.getAbsoluteValue(), "CORN" 
		});
	}

	@Override
	public void changeCorn(TZResource r) throws NotEnoughCornException {
		if (isWaitingForTurn() != 0) {
			throw new IllegalStateException();
		}
		if (r == null) {
			throw new IllegalArgumentException();
		}
		if (getPlayersManager().getCurrent().getCorn() < r.getAbsoluteValue() || !canExchange()) {
			throw new IllegalStateException();
		}
		getCurrentPlayer().getWallet().addResource(r);
		getCurrentPlayer().removeCorn((int) r.getAbsoluteValue());
		getLog().addSentence(new String[] {
			getCurrentPlayer().getName(), "CHANGE", "" + (int) r.getAbsoluteValue(), "CORN", "FOR", "1", r.toString()
		});
	}
	
	@Override
	public ITZPlayer endTurn() throws WaitingOperationsException, EndOfGameException, NoMovedWorkersException {
		if (isWaitingForTurn() != 0 || downTemples > 0) {
			throw new WaitingOperationsException();
		}
		initPermissions();
		return super.endTurn();
	}
	
	@Override
	public void incTurn(int d) throws EndOfGameException, WaitingOperationsException {
		if (isWaitingForTurn() == 0 || (d > MINIMUM_DAY_TURN && getFirstWorker() != null && !getFirstWorker().getOwner().canTurnTwice())) {
			throw new IllegalStateException();
		}
		// Jour de festin
		Season feedingDay = getTurnsCounter().feedingDay(); 
		if (feedingDay != null) {
			if (feedingDay.changeBuildings()) {
				buildings.clear();
				getBank().setSecondPeriod();
				getLog().addSentence(new String[] {
					"THE_BUILDINGS", "OF", "SECOND_PERIOD", "ARE", "AVAILABLE"	
				});
				listeners.firePropertyChange("buildings", null, null);
			}
		}
		super.incTurn(d);
	}
	
	@Override
	public void downTemple(ITZPlayer p, ITemple t) throws StepMoveException {
		if (downTemples <= 0) {
			throw new IllegalStateException();
		}
		super.downTemple(p, t);
		setDownTemples(downTemples - 1);
		listeners.firePropertyChange("begforcorn", true, false);
	}

	@Override
	public void setTechEvolve(int i, boolean mustPay) {
		if (i < 0) {
			throw new IllegalArgumentException();
		}
		upTechs = i;
		mustPayTech = mustPay;
		listeners.firePropertyChange("techEvolve", -1, i);
	}
	
	@Override
	public void setDownTemples(int i) {
		if (i < 0) {
			throw new IllegalArgumentException();
		}
		int downableMarches = 0;
		for (ITemple t : TempleEnum.values()) {
			downableMarches += getTemplesManager().getPosition(t, getCurrentPlayer());
		}
		downTemples = Math.min(downableMarches, i);
		listeners.firePropertyChange("mustDownTemple", -1, downTemples);
	}

	@Override
	public void setUpTemples(int i) {
		if (i < 0) {
			throw new IllegalArgumentException();
		}
		int upableMarches = 0;
		for (ITemple t : TempleEnum.values()) {
			if (getTemplesManager().canUp(t, getCurrentPlayer())) {
				differentTemples.add(t);
				upableMarches += t.getHeight() - 1 - getTemplesManager().getPosition(t, getCurrentPlayer());
			}
		}
		upTemples = Math.min(upableMarches, i);
		listeners.firePropertyChange("canUpTemple", -1, i);
	}

	@Override
	public void setUpDifferentTemples(int i) {
		if (i < 0) {
			throw new IllegalArgumentException();
		}
		upDifferentTemples = i;
		if (i > 0) {
			if (differentTemples.size() == 0) {
				differentTemples.clear();
				for (ITemple t : TempleEnum.values()) {
					if (getTemplesManager().canUp(t, getCurrentPlayer())) {
						differentTemples.add(t);
					}
				}
			}
		}
		listeners.firePropertyChange("canUpTemple", -1, upDifferentTemples);
	}

	@Override
	public void setExchange(boolean can) {
		boolean old = canExchange;
		canExchange = can;
		listeners.firePropertyChange("canExchange", old, canExchange);
	}

	@Override
	public void setCollectResource(int qty) {
		if (qty < 0) {
			throw new IllegalArgumentException();
		}
		collectResource = qty;
		listeners.firePropertyChange("techEvolve", 0, collectResource);
	}
	
	// OUTILS
	
	protected boolean mustPayTech() {
		return mustPayTech;
	}
	
	protected void initPayTech() {
		mustPayTech = false;
	}
	
	private void initPermissions() {
		setBuildBuildings(0);
		setBuildMonuments(0);
		setTechEvolve(0, false);
		setUpTemples(0);
		setUpDifferentTemples(0);
		canExchange = false;
		collectResource = 0;
	}

}
